package com.springboot.demo.utils;

/**
 * @author wubc683
 * @desc 短信验证码
 * @date 2021-07-30 10:26
 */

import java.util.Random;

import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.springboot.demo.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;

@Component
@Slf4j
public class SmsCodeUtils {
    public static final String SMSTIMES = "SMSTIMES::";
    public static final String SMSCODE = "SMSCODE::";
    public static final String REGISTERIP = "REGISTERIP::";
    // 短信验证码有效期内最大发送次数
    public static final Long SMS_MAX_TIMES = 50L;
    // 同一个ip一天最多注册次数
    public static final Integer IP_REGISTER_MAX_TIMES = 50;
    // 短信验证码有效期(单位：秒）
    public static final Long SMS_CODE_TIMEOUT = 360L;
    private DefaultProfile profile;
    private CommonRequest request;
    private IAcsClient client;
    @Autowired
    RedisUtils redisUtils;

    public SmsCodeUtils() {
        profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI4G3DA3VsMuZLNVdRRnk3", "QNdvHpyvfOqM30TA7mZ3iESyphGB0J");
        client = new DefaultAcsClient(profile);
        request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain("dysmsapi.aliyuncs.com");
        request.setSysVersion("2017-05-25");
        request.setSysAction("SendSms");
        request.putQueryParameter("SignName", "合信技术");
        request.putQueryParameter("TemplateCode", "SMS_140625111");
    }

    /**
     * 发送短信验证码
     *
     * @param registerIp
     * @param phone
     * @return: void
     */
    @Transactional(rollbackFor = Exception.class)
    public void send(String registerIp, String phone) {
        if (!CommonUtils.checkPhone(phone)) {
            throw new BusinessException(ResponseResult.PHONE_FORMAT_ERROR);
        }
        // 检查ip注册次数，一个ip一天注册最多5次
        Object o = redisUtils.get(REGISTERIP + registerIp);
        if(o != null){
            int regTimes = Integer.parseInt(o.toString());
            if(regTimes >= IP_REGISTER_MAX_TIMES){
                throw new BusinessException(ResponseResult.REGISTER_TOO_MUCH);
            }
            redisUtils.setRange(REGISTERIP+registerIp,regTimes+1,0L);
        }else{
            redisUtils.set(REGISTERIP+registerIp,1,24*60*60L);
        }
        // 检查是否短信验证码发送太频繁，间隔60秒以上
        Long expire = redisUtils.getExpire(SMSCODE + phone);
        if(SMS_CODE_TIMEOUT-expire < 60){
            throw new BusinessException(ResponseResult.SMS_SHORTER_THAN_MAX_INTERVAL);
        }
        // 检查手机号短信发送次数是否超过最大允许次数,一个手机号一天只能发送5次短信验证码
        Object object = redisUtils.get(SMSTIMES + phone);
        if (object == null) {
            redisUtils.set(SMSTIMES + phone, 1, 24*60*60L);
            // 连接阿里云服务器，发送短信验证码
            String code = createSmsCode(phone);
            redisUtils.set(SMSCODE + phone, code, SMS_CODE_TIMEOUT);
        } else {
            int phoneTimes = Integer.parseInt(object.toString());
            if (phoneTimes >= SMS_MAX_TIMES) {
                throw new BusinessException(ResponseResult.SMS_COUNT_LIMITED);
            }
            String code = createSmsCode(phone);
            redisUtils.set(SMSCODE + phone, code, SMS_CODE_TIMEOUT);
            redisUtils.setRange(SMSTIMES+phone,phoneTimes+1,0L);
        }
    }

    /**
     * 校验短信验证码
     *
     * @param phone
     * @param smsCode
     * @return: void
     */
    public void check(String phone, String smsCode) {
        Object object = redisUtils.get(SMSCODE + phone);
        if (object == null) {
            throw new BusinessException(ResponseResult.SMS_ERROR);
        }
        String querySmsCode = object.toString();
        if (!smsCode.equals(querySmsCode)) {
            throw new BusinessException(ResponseResult.SMS_ERROR);
        }
    }

    /**
     * 创建短信验证码
     *
     * @param phone
     * @return: java.lang.String
     */
    private String createSmsCode(String phone) {
//        String param = "{\"code\"}";
        Random r = new Random();
        int ran = 100000 + r.nextInt(900000);

//        String str = "{\"code\":" + String.valueOf(ran) + "}";
        request.putQueryParameter("TemplateParam", "{\"code\":" + String.valueOf(ran) + "}");
        request.putQueryParameter("RegionId", "cn-hangzhou");
        request.putQueryParameter("PhoneNumbers", phone);
        try {
            client.getCommonResponse(request);
        } catch (Exception e) {
            log.error("短信发送服务异常,phone={}", phone);
            throw new BusinessException(ResponseResult.SMS_SERVER_ERROR);
        }
        return String.valueOf(ran);
    }

    /**
     * 删除验证码
     *
     * @param phone
     * @return: void
     */
    public void del(String phone) {
        redisUtils.delete(SMSCODE + phone);
    }

}